package service

import (
	"strings"
	"time"

	"gitee.com/sansaniot/ssiot-core/sdk/service"
	"gorm.io/gorm"

	"ssdevice/common/constant"
	cDto "ssdevice/common/dto"
	"ssdevice/common/enums"
	"ssdevice/common/utils"
	"ssdevice/internal/device/models"
	"ssdevice/internal/device/models/command"
	"ssdevice/internal/device/models/query"
)

type Product struct {
	devProductModel *models.SysDevProduct
	devSchemaModel  *models.SysDevSchema
	devConfigModel  *models.SysDevConfig
	devModel        *models.SysDev
	service.Service
}

func (d *Product) SetProductModel(m *models.SysDevProduct) *Product {
	d.devProductModel = m
	return d
}

func (d *Product) SetSchemaModel(m *models.SysDevSchema) *Product {
	d.devSchemaModel = m
	return d
}

func (d *Product) SetConfigModel(m *models.SysDevConfig) *Product {
	d.devConfigModel = m
	return d
}

func (d *Product) SetDevModel(m *models.SysDev) *Product {
	d.devModel = m
	return d
}

func (d *Product) SetAllModel() {
	d.devProductModel = &models.SysDevProduct{}
	d.devSchemaModel = &models.SysDevSchema{}
	d.devConfigModel = &models.SysDevConfig{}
	d.devModel = &models.SysDev{}
	d.devProductModel.Orm = d.Orm
	d.devSchemaModel.Orm = d.Orm
	d.devConfigModel.Orm = d.Orm
	d.devModel.Orm = d.Orm
}

func generateProductSchema(product models.SysDevProduct, devSchema *models.SysDevSchema) *models.SysDevSchema {
	now := cDto.LocalTime(time.Now())
	schemaData := []byte(utils.If(product.DeviceType == enums.DevTypeOfDevice, constant.DevSchemaTemplate, constant.GatewaySchemaTemplate).(string))
	if devSchema != nil {
		schemaData = devSchema.Schema
	}
	return &models.SysDevSchema{
		Id:           utils.SimpleUUID(),
		Schema:       schemaData,
		ProductModel: product.ProductModel,
		DevProductId: product.Id,
		CreateTime:   &now,
		UpdateTime:   &now,
	}
}

func generateProductConfig(product models.SysDevProduct, devConfig *models.SysDevConfig) *models.SysDevConfig {
	now := cDto.LocalTime(time.Now())
	configData := []byte(utils.If(product.DeviceType == enums.DevTypeOfDevice, constant.DevConfigTemplate, constant.GatewayConfigTemplate).(string))
	if devConfig != nil {
		configData = devConfig.Data
	}
	return &models.SysDevConfig{
		Id:           utils.SimpleUUID(),
		Data:         configData,
		ProductModel: product.ProductModel,
		DevProductId: product.Id,
		CreateTime:   &now,
		UpdateTime:   &now,
	}
}

// 添加产品
func (d *Product) AddProduct(req *command.ProductInsertReq) (err error, product models.SysDevProduct) {
	if err = req.Generate(&product); err != nil {
		return
	}
	err = d.Orm.Transaction(func(tx *gorm.DB) error {
		// 事务orm
		d.devProductModel.Orm = tx
		d.devSchemaModel.Orm = tx
		d.devConfigModel.Orm = tx
		// 产品基本信息
		if err = d.devProductModel.AddProduct(&product); err != nil {
			return err
		}
		// 产品schema
		if err = d.devSchemaModel.Add(generateProductSchema(product, req.DevSchema)); err != nil {
			return err
		}
		// 产品config
		if err = d.devConfigModel.Add(generateProductConfig(product, req.DevConfig)); err != nil {
			return err
		}
		return nil
	})
	return
}

// 删除产品
func (d *Product) DeleteProduct(req *command.ProductDeleteReq) (err error) {
	if err = d.Orm.Transaction(func(tx *gorm.DB) error {
		// 事务orm
		d.devModel.Orm = tx
		d.devProductModel.Orm = tx
		d.devSchemaModel.Orm = tx
		d.devConfigModel.Orm = tx
		// 批量操作
		delIds := strings.Split(strings.ReplaceAll(req.Id, " ", ""), ",")
		// 置空关联设备的productModel字段
		if err = d.devProductModel.SetRelateDevCodeEmpty(delIds); err != nil {
			return err
		}
		// 产品信息
		if err = d.devProductModel.Delete(d.devProductModel, cDto.MakeCondition(query.SysProductQuery{IdIn: delIds})); err != nil {
			return err
		}
		// 产品schema
		if err = d.devSchemaModel.Delete(d.devSchemaModel, cDto.MakeCondition(query.SysDevSchemaQuery{ProductIdIn: delIds})); err != nil {
			return err
		}
		// 产品config
		if err = d.devConfigModel.Delete(d.devConfigModel, cDto.MakeCondition(query.SysDevConfigQuery{ProductIdIn: delIds})); err != nil {
			return err
		}
		return nil
	}); err != nil {
		return
	}
	return
}

// 产品复制
func (d *Product) ProductCopy(req *command.ProductCopyReq) (one models.SysDevProduct, err error) {
	product := models.SysDevProduct{}
	if err = d.devProductModel.FindOne(&product, cDto.MakeCondition(query.SysProductQuery{Id: req.Id})); err != nil {
		return
	}
	productInsert := command.ProductInsertReq{}
	req.GenerateProduct(&product, &productInsert)
	// 查询产品schema
	if err = d.devSchemaModel.FindOne(d.devSchemaModel, cDto.MakeCondition(query.SysDevSchemaQuery{ProductId: product.Id})); err != nil {
		return
	}
	// 查询产品config
	if err = d.devConfigModel.FindOne(d.devConfigModel, cDto.MakeCondition(query.SysDevConfigQuery{ProductId: product.Id})); err != nil {
		return
	}
	productInsert.DevSchema = d.devSchemaModel
	productInsert.DevConfig = d.devConfigModel
	// 添加产品
	sp := &Product{}
	sp.Orm = d.Orm
	sp.SetAllModel()
	err, one = sp.AddProduct(&productInsert)
	return
}
